<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <script>
        // 一、编程范式：计算机编程的代码风格
        // 二、编程范式分类：命令式编程和声明式编程
        // （一）命令式编程：以命令为主，给机器命令，控制机器如何去做
        // 涉及语言：C语言、C++、Java、JavaScript
        // 命令式编程分类
        // 1.面向过程：把整个程序分解成步骤，一步步实现（蛋炒饭）
        // 优点：页面性能比面向对象高，因为对象越多，占用内存越大，页面开销就大，所以面向对象比较消耗资源；高耦合
        // 缺点：程序的扩展性、复用效率没有面向对象高，程序不容易维护

        // 耦合：在软件工程中,耦合表示子系统之间的关联度，当一个子系统发送变化时，对另一个子系统的影响很小，就称他们为低耦合；
        // 反之，如果影响很大，就称他们是高耦合

        // 2.面向对象：把整个程序拆分成各个小的对象（盖浇饭）
        // 优点：低耦合，程序容易维护、容易复用、容易扩展
        // 缺点：页面性能低于面向过程

        // 注意：项目中会同时使用面向过程和面向对象的编程方式

        // （二）声明式编程：告诉机器想要的结果，机器自己去做
        // 声明式编程分类：DSL（HTML、css、sql）和函数式编程

        // 三、描述对象（创建对象）
        // 1.外观被作为对象的属性：值不是函数
        // 2.功能被作为对象的方法:值是函数

        // 四、面向对象的三大特点
        // 1.封装：把内部运作隐藏在对象中，只有最基本的功能暴露给用户
        // 2.继承：采用一个对象的特征，然后添加一些新的特征
        // 3.多态：相同的功能可以用于不同的对象

        // 五、类
        // 概念：类是对对象的一种概括，而对象是类的一种具体实现
        // 举例：类——学生；对象——张三、李四、王五
        //      类——汽车；对象——车牌号为xxxx的大众汽车

        // 六、对象分类
        // 1.原生对象：内置对象：Math\Date；自定义对象
        // 2.宿主对象：window\history
        // 3.普通对象：具有JS对象所有默认内部行为
        // 4.外来对象：引入外部的对象
        // 5.标准对象：Math\Date

        // 七、如何创建一个对象？
        // 1.字面量创建对象:是构造函数创建对象的语法糖
        // let obj={};
        // 2.构造函数创建对象
        // let obj=new Object();

        // 语法糖：简写，本质是相同的，只是书写方式更加简单

        // 八、构造函数
        // 1.概念：构造函数也是函数，和普通函数外表相同，声明方式相同，区别只是在于调用方式不同
        // 2.和普通函数的区别：
        // （1）构造函数调用： new 函数名(),构造函数调用必须叫new关键字
        // (2)构造函数的主要作用是生产对象，因此在构造函数内部会自动生成一个空对象，
        //    在构造函数里面使用this，this就指向这个空对象，因此this={}
        // (3)构造函数的默认返回值是对象(就是构造函数内容自动生成的那个对象);
        //    如果要修改返回值，可以使用return返回复杂数据类型，不能返回简单数据类型
        // (4)为了区分普通函数和构造函数，构造函数的声明的时候，首字母需要大写（约定俗成）
        // (5)在JavaScript中，在ES6之前是没有类这个概念的，就是通过构造函数来实现类


        // function Test(){
        //     // this={}
        //     // this.xyz=123;
        //     // console.log(this);
        //     console.log(123);
        //     return [66,77];
        // }

        // // test();//普通函数调用
        // let s=new Test();//test是构造函数
        // console.log(s);

        // Date()：返回日期时间字符串
        // new Date():返回日期时间对象


        // 九、如何批量创建对象？
        // 1.工厂模式
        // function createStudent(name,age,score,classNumber) {
        //     let obj = {
        //         name,
        //         age,
        //         score,
        //         classNumber
        //     }
        //     return obj;
        // }
        // function createStudent2(name,age,score,classNumber) {
        //     let obj = {
        //         name,
        //         age,
        //         score,
        //         classNumber

        //     }
        //     return obj;
        // }
        // let s1=createStudent("张三",18,88,2);
        // let s2=createStudent2("李四",19,78,2);
        // let s3=createStudent("王五",19,77,2);
        // console.log(typeof s1);
        // console.log(typeof s2);
        // console.log(typeof s3);
        // 工厂模式的缺点：获取不到最真实的数据来源，都是object;每一次调用都会生成一个新的对象

        // 2.自定义构造函数批量创建对象
        // function CreateStudent(name,age,score,classNumber) {
        //     // this={}
        //     this.name=name;
        //     this.age=age;
        //     this.score=score;
        //     this.classNumber=classNumber;
        //     this.fn=function(){
        //         console.log(name+"在写作业~~~");
        //     }
        // }
        // let s1=new CreateStudent("张三",18,88,2);
        // let s2=new CreateStudent("李四",19,78,2);
        // console.log(typeof s1);
        // console.log(typeof s2);

        // 3.构造函数+原型
        // function CreateStudent(name,age,score,classNumber) {
        //     // this={}
        //     this.name=name;
        //     this.age=age;
        //     this.score=score;
        //     this.classNumber=classNumber;
        //     // return {test:666}  
        //     // 注意：如果构造函数的返回值是自定义对象，那么实例化出来的对象也就是自定义对象，不再是this对象
        // }
        // 在原型上添加方法
        // CreateStudent.prototype.fn=function(){
        //     console.log(this.name+"在写作业~~~");
        // }
        // let s1=new CreateStudent("张三",18,88,2);
        // let s2=new CreateStudent("李四",18,88,2);
        // console.log(s1);
        // console.log(s2);
        // s1.fn();
        // s2.fn();
        // console.log(s1.fn===s2.fn);//true  表示使用同一个方法

        // 

        // // 十、原型对象
        // // 1.构造函数实例化对象  let foo=new Foo();
        // function Foo(){
        //     console.log("构造函数");
        //     this.name="Foo";
        // }
        // let foo=new Foo();

        // // let obj={xyz:123};
        // // console.log(obj);
        // // console.log(obj.__proto__);

        // // 2.对象的原型对象（对象原型）：在js中每一个对象里面都自带一个属性[[Prototype]],该属性被称为原型对象，该属性的值依然是一个对象
        // //   如果要访问原型对象，就通过__proto__这个属性名来访问
        // console.log("对象原型:", foo.__proto__);
        // // 原型链：只要是对象，都会有原型对象，可以通过__proto__这个属性名访问，一直往上，直到null
        // console.log("对象原型:", foo.__proto__.__proto__.__proto__);//null

        // // 3.函数的原型对象（函数原型）：每一个构造函数都有一个函数原型对象，可以通过prototype属性名来访问
        // console.log("函数原型",Foo.prototype);

        // // 4.对象原型和函数原型全等
        // console.log(foo.__proto__===Foo.prototype);
        // // 5.对象原型和函数原型里面有一个constructor属性，该属性指向构造函数本身
        // console.log(foo.__proto__.constructor===Foo);

        // foo.__proto__.age=88;
        // console.log(foo);
        // // 对象中的属性或方法找不到的话，就回去原型中招，直到最顶层的null
        // console.log(foo.age);//88

        // 十一、类
        // 1.在es6之前，JavaScript中没有类的概念，是使用构造函数模拟类，创造对象
        // 2.在es6之后，JavaScript中新增专用的class关键字来创建类，但是这只是语法糖，本质依然是使用原型创建对象

        // // 基本语法
        // class CreateStudent{
        //     // 构造器：对象属性
        //     constructor(name,age,score){
        //         this.name=name;
        //         this.age=age;
        //         this.score=score;
        //     }
        //     // 方法：添加在原型上面
        //     fn(){
        //         console.log(this.name +"在写作业~~");
        //     }
        // }

        // // 实例化
        // let s1=new CreateStudent("张三",18,99);
        // console.log(s1);

        // 十二：面向对象的三大特点
        // 1.封装：把一些变量变成私有变量，只能在构造函数内部使用
        // 2.继承：子类继承父类的属性和方法
        //         如果多个子类有相同的属性或者方法，可以考虑创建一个共同的父类，把相同的属性或方法写在父类里面，实现继承
        //         这样就可以实现代码复用，提高效率
        // 继承分类：单继承（一个父类：JS）
        //          多继承（多个父类：C语言）
        // 实现继承的具体方法：
        // （1）对象冒充：无法继承绑定在父类构造函数的函数原型上面的方法（不使用）
        // （2）方法借用：无法继承绑定在父类构造函数的函数原型上面的方法（不使用）

        // 掌握：
        // call()和apply(),这两个方法主要用于修改函数的this指向，本质效果相同，只是传入的参数写法不同
        // 使用方法：
        // 函数.apply(this指向的对象，数组)
        // 函数.call(this指向的对象,参数1，参数2....)


        // this指向：
        // 1.以函数形式调用，this永远指向window
        // 2.以方法形式调用，this指向调用该方法的对象
        // 3.以new关键字调用函数，this指向构造函数内部自动创建的对象

        // function test(x,y){
        //     console.log(this);
        //     console.log(x+y);
        //     return 123;
        // }
        // test(1,2);//this=window
        // let x=test.call({a:333},1,2);//this={a:333}  x=1,y=2
        // console.log(x);//123
        // test.call(444,1,2);//this={444}  x=1,y=2  
        // // 注意：this永远指向对象，如果传入的参数不是对象，会自动转为对象
        // test.apply({b:456},[1,2]);//this={b:456},x=1,y=2
        // test.apply(888,[1,2]);//this={b:456},x=1,y=2

        // let arr = [3, 15, 8, 1, 2, 17, 11];
        // console.log(Math.max(...arr));


        // （3）原型继承(ES6之前实现继承的最佳方案)
        // 父类
        // function Father(name,age){
        //     this.name=name;
        //     this.age=age;
        // }
        // // 把公共方法绑定在父类上
        // Father.prototype.fn=function(){
        //     console.log("公共方法");
        // }
        // // 子类
        // function Son(name,age,classNumber){
        //     // 把Father构造函数里面的this指向改成和Son构造函数里面的this指向相同
        //     Father.apply(this,[name,age]);
        //     this.classNumber=classNumber;
        // }
        // // 把Son构造函数的函数原型修改为Father构造函数的实例化对象
        // Son.prototype=new Father();
        // let s=new Son("张三",18,9);
        // console.log(s);

        // （4）终极方案实现继承：ES6的继承写法（本质上就是原型继承方法的语法糖）
        // 父类
        // class Father{
        //     // 属性
        //     constructor(name,age){
        //         this.name=name;
        //         this.age="16";
        //     }
        //     // 原型方法
        //     fn(){
        //         console.log("father");
        //     }

        // }
        // // 子类继承父类
        // class Son extends Father{
        //     // 属性
        //     constructor(name,age,classNumber){
        //         // 访问父类里面的属性
        //         super(name,age);
        //         // this.age=age;
        //         this.classNumber=classNumber;
        //     }
        //     // 原型方法
        //     foo(){
        //         console.log("son");
        //     }
        //     // 如果子类的原型方法和父类的原型方法名字相同，优先访问子类原型方法
        //     fn(){
        //         console.log("son2");
        //     }


        // }
        // // 实例化对象
        // let s=new Son("张三",18,3);
        // console.log(s);
        // s.fn();

        // 3.多态：同一操作作用于不同的对象上面，可以产生不同的解释和不同的执行结果

        

















        


    </script>
</body>

</html>